#include "polygon.hpp"

#include "qbe/src/ecs/app.hpp"

#include "qbe/src/ecs/query.hpp"

#include "qbe/src/axis/axis.hpp"
#include "qbe/src/input/input.hpp"
#include "qbe/src/select/select.hpp"
#include "qbe/src/state/state.hpp"
#include "qbe/src/undoRedo/undoRedo.hpp"
#include "qbe/src/utils/utils.hpp"

#include "qbe/src/layout/layout.hpp"

#include "qlib/all.h"

#include "../components.hpp"
#include "../events.hpp"

#include "../../render/components.hpp"

#include "../../utils/utils.hpp"

#include <QMessageBox>

#include "../../operationLayer/operationLayer.h"

namespace qbe::draw::polygon {

// 帧尾-移除标记
void clear_tag(ecs::Query query) {
  auto& param = query.get_resource<Models>();

  // 遍历模块所有Tag并移除
  if (param.clear_tag) {
    auto& cell = query.get_resource<qlib::Cell::s_ptr>();
    auto& reg = cell->reg;

    auto view_cache_add = reg.view<PolygonCacheAddTag>();
    view_cache_add.each([&reg](entt::entity e) { reg.remove<PolygonCacheAddTag>(e); });

    auto view_cache_update = reg.view<PolygonCacheUpdateTag>();
    view_cache_update.each([&reg](entt::entity e) { reg.remove<PolygonCacheUpdateTag>(e); });

    auto view_cache_delete = reg.view<PolygonCacheDeleteTag>();
    view_cache_delete.each([&reg](entt::entity e) { reg.remove<PolygonCacheDeleteTag>(e); });

    auto view_add = reg.view<PolygonAddTag>();
    view_add.each([&reg](entt::entity e) { reg.remove<PolygonAddTag>(e); });

    param.clear_tag = false;
  }
}

// 添加临时对象
void add_cache_obj(entt::registry& reg, ecs::EventWriter<draw::Event> event_writer, layout::LayoutCmd& cmd, entt::entity entity, Models& models,
                   ecs::Query query) {
  auto polygon = reg.get<qlib::Polygon::s_ptr>(entity);

  models.polygon = render::PolyLineMesh(polygon->points, true);

  auto& ol = query.get_resource<ol::Models>();
  ol.clearAllSelect();

  event_writer.send({Code::PolygonCacheAdd});

  if (models.complete_entity != entt::null) {
    reg.remove<select::SelectTag>(models.complete_entity);
    auto& sele_event_writer = query.get_event_writer<select::Event>();
    sele_event_writer.send({select::Code::SelectUpdate});
    sele_event_writer.send({select::Code::HoverUpdate});

    models.complete_entity = entt::null;
  }
}

// 更新临时对象
void update_cache_obj(entt::registry& reg, ecs::EventWriter<draw::Event> event_writer, layout::LayoutCmd& cmd, entt::entity entity, Models& models) {
  auto polygon = reg.get<qlib::Polygon::s_ptr>(entity);

  models.polygon = render::PolyLineMesh(polygon->points, true);

  event_writer.send({Code::PolygonCacheUpdate});
}

// 删除临时对象
void delete_cache_obj(entt::registry& reg, ecs::EventWriter<draw::Event> event_writer, layout::LayoutCmd& cmd, entt::entity entity, Models& models) {
  reg.destroy(entity);

  event_writer.send({Code::PolygonCacheDelete});
}

// 添加对象
void add_obj(entt::registry& reg, ecs::EventWriter<draw::Event> event_writer, layout::LayoutCmd& cmd, entt::entity entity,
             undoRedoT::UndoRedoModule& undoRedoModuel, qlib::Cell::s_ptr cell, Models& models, ecs::Query query, state::State& state) {
  auto polygon = reg.get<qlib::Polygon::s_ptr>(entity);
  bool have_layer = state.getCurrentLayer(polygon->layer);

  if (have_layer) {
    auto e = cmd.add(polygon);
    models.complete_entity = e;

    undoRedoModuel.start(cell);
    undoRedoModuel.add(e);
    undoRedoModuel.end();

    models.clear_tag = true;
    reg.emplace<PolygonAddTag>(e);
    event_writer.send({Code::PolygonAdd});

    reg.emplace_or_replace<select::SelectTag>(e);
    auto& sele_event_writer = query.get_event_writer<select::Event>();
    sele_event_writer.send({select::Code::SelectUpdate});
    sele_event_writer.send({select::Code::HoverUpdate});
  }

  delete_cache_obj(reg, event_writer, cmd, entity, models);
}

// 退出绘制模式时手动调用
void exit_callback(ecs::Query query, state::AllModeType new_mode) {
  // 获取参数
  auto& param = query.get_resource<Models>();

  if (param.complete_entity != entt::null && !state::isModeType<state::EditingModeType>(new_mode)) {
    auto& cell = query.get_resource<qlib::Cell::s_ptr>();
    auto& reg = cell->reg;

    reg.remove<select::SelectTag>(param.complete_entity);
    auto& sele_event_writer = query.get_event_writer<select::Event>();
    sele_event_writer.send({select::Code::SelectUpdate});
    sele_event_writer.send({select::Code::HoverUpdate});

    param.complete_entity = entt::null;
  }

  // 如果正在绘制
  if (param.state != State::None && param.entity != entt::null) {
    // 获取cell和reg
    auto& cell = query.get_resource<qlib::Cell::s_ptr>();
    auto& reg = cell->reg;
    auto& cmd = query.get_resource<layout::LayoutCmd>();
    auto& models = query.get_resource<Models>();

    // 获取事件写入器
    auto event_writer = query.get_event_writer<draw::Event>();

    // 外部通知删除
    delete_cache_obj(reg, event_writer, cmd, param.entity, models);

    // 重置参数
    param.state = State::None;
    param.entity = entt::null;

    auto& absorbModule = query.get_resource<qbe::adsorb::AdsorbModel>();
    absorbModule.close_diagonal_start();
  } else {
    // 重置参数
    param.state = State::None;
    param.entity = entt::null;

    auto& absorbModule = query.get_resource<qbe::adsorb::AdsorbModel>();
    absorbModule.close_diagonal_start();
  }
}

// 退出绘制模式时手动调用
void exit(ecs::Query query) {
  // 获取参数
  auto& param = query.get_resource<Models>();

  if (param.complete_entity != entt::null) {
    auto& cell = query.get_resource<qlib::Cell::s_ptr>();
    auto& reg = cell->reg;

    reg.remove<select::SelectTag>(param.complete_entity);
    auto& sele_event_writer = query.get_event_writer<select::Event>();
    sele_event_writer.send({select::Code::SelectUpdate});
    sele_event_writer.send({select::Code::HoverUpdate});

    param.complete_entity = entt::null;
  }

  // 如果正在绘制
  if (param.state != State::None && param.entity != entt::null) {
    // 获取cell和reg
    auto& cell = query.get_resource<qlib::Cell::s_ptr>();
    auto& reg = cell->reg;
    auto& cmd = query.get_resource<layout::LayoutCmd>();
    auto& models = query.get_resource<Models>();

    // 获取事件写入器
    auto event_writer = query.get_event_writer<draw::Event>();

    // 外部通知删除
    delete_cache_obj(reg, event_writer, cmd, param.entity, models);

    // 重置参数
    param.state = State::None;
    param.entity = entt::null;

    auto& absorbModule = query.get_resource<qbe::adsorb::AdsorbModel>();
    absorbModule.close_diagonal_start();
  } else {
    // 重置参数
    param.state = State::None;
    param.entity = entt::null;

    auto& absorbModule = query.get_resource<qbe::adsorb::AdsorbModel>();
    absorbModule.close_diagonal_start();

    // 退出模式
    auto& state = query.get_resource<state::State>();
    state.exit();
  }
}

// 初始化
void init(ecs::Commands command, ecs::Query query) {
  // 添加参数到资源
  Models param;
  command.insert_resource(param);

  // 添加模式退出回调
  auto& state = query.get_resource<state::State>();
  state.addExitCall(state::DrawingModeType::Polygon, exit_callback);
}

// 帧开始，模式转换
void stateTransformBegin(State& state, input::HandleBundle* handle) {
  // 执行操作的状态完成则回退，不存在维持情况
  assert(state == State::None || state == State::Begin);

  // 按下ecs必然回退
  if (handle->keyReleased(vsg::KEY_Escape)) {
    state = State::Cancel;
    return;
  }

  // 左键按下必然响应
  if (handle->mousePressed(vsg::ButtonMask::BUTTON_MASK_1)) {
    state = State::Create;
    return;
  }

  // 右键按下在已经绘制对象时，必须响应
  if (state == State::Begin && handle->mousePressed(vsg::ButtonMask::BUTTON_MASK_3)) {
    state = State::Complete;
    return;
  }

  // 回车
  if (state == State::Begin && handle->keyReleased(vsg::KEY_Return)) {
    state = State::Complete;
    return;
  }

  // 最低优先级，移动
  if (state == State::Begin && handle->mouse_move) {
    state = State::Upatde;
    return;
  }
}

// 帧尾-退出模式
void stateTransformEnd(State& state) {
  // 操作模式执行完就应该回退
  if (state == State::Create || state == State::Upatde || state == State::Complete || state == State::Cancel) {
    state = State::Begin;
  }
}

// 获取鼠标当前点，需要考虑：吸附、斜角吸附
qlib::Vec2d getNowPoint(ecs::Query query, qlib::Vec2d prePoint) {
  {
    auto& axisModule = query.get_resource<axis::Axis>();
    qlib::Vec2d pos = {axisModule.real_x, axisModule.real_y};

    auto& absorbModule = query.get_resource<qbe::adsorb::AdsorbModel>();
    absorbModule.set_diagonal_start(prePoint);

    return pos;
  }

  auto& state = query.get_resource<state::State>();

  if (!state.isAdsorption()) {
    if (!state.isAngleTheAdsorption()) {
      auto& axisModule = query.get_resource<axis::Axis>();
      qlib::Vec2d pos = {axisModule.real_x, axisModule.real_y};
      return pos;
    } else {
      auto& axisModule = query.get_resource<axis::Axis>();
      qlib::Vec2d pos = {axisModule.real_x, axisModule.real_y};
      return utils::getAngleAdsorbedPoint(prePoint, pos);
    }
  } else {
    if (!state.isAngleTheAdsorption()) {
      return utils::getAdsorbedPoint(query);
    } else {
      qlib::Vec2d pos = utils::getAdsorbedPoint(query);
      return utils::getAngleAdsorbedPoint(prePoint, pos);
    }
  }
}

// 更新函数
void update(ecs::Query query) {
  // 判断编辑模式为绘制
  auto& state = query.get_resource<state::State>();

  if (state.getDrawingMode() != state::DrawingModeType::Polygon)
    return;

  {
    auto& ol = query.get_resource<ol::Models>();

    uint32_t currentLayer = 0;
    if (state.getCurrentLayer(currentLayer)) {
      bool currentLayerHide = ol.currentLayerIsHide(currentLayer);
      if (currentLayerHide) {
        exit(query);
        return;
      }
    }
  }

  auto& select_models = query.get_resource<select::OverallModel>();
  // select_models.mouse_press = false;
  // select_models.mouse_release = false;

  // 获取cell cmd
  auto& layout_cmd = query.get_resource<layout::LayoutCmd>();

  // 获取cell和reg
  auto& cell = query.get_resource<qlib::Cell::s_ptr>();
  auto& reg = cell->reg;

  // 获取输入 坐标系 撤销恢复
  auto& handModule = query.get_resource<vsg::ref_ptr<input::HandleBundle>>();
  auto& axisModule = query.get_resource<axis::Axis>();
  auto& undoRedoModule = query.get_resource<undoRedoT::UndoRedoModule>();

  // 获取参数
  auto& param = query.get_resource<Models>();
  auto& entity = param.entity;

  // 获取事件写入器
  auto event_writer = query.get_event_writer<draw::Event>();

  // 开始的状态转换
  stateTransformBegin(param.state, handModule);

  // 获取当前鼠标点
  layout::Vec2d pos = {axisModule.real_x, axisModule.real_y};

  {
    uint32_t layer;
    if (!state.getCurrentLayer(layer)) {
      QMessageBox::information(nullptr, QObject::tr("error"), QObject::tr("No layer selected, unable to draw"));
      exit(query);
    }
  }

  if (param.state == State::Cancel)
    exit(query);

  // 创建流程
  if (param.state == State::Create) {
    // 对象为空则新建
    if (entity == entt::null) {
      // 新建实体和指针
      entity = reg.create();
      auto polygon_ptr = qlib::Polygon::create();

      // 绑定指针到实体
      reg.emplace<qlib::Polygon::s_ptr>(entity, polygon_ptr);

      // 获取多边形点集
      auto& points = polygon_ptr->points;

      // 添加两个点
      points.emplace_back(pos);
      points.emplace_back(pos);

      // 通知外部添加
      add_cache_obj(reg, event_writer, layout_cmd, entity, param, query);
      param.clear_tag = true;
    } else {
      if (param.is_moveing) {
        // 对象不为空则获取
        auto& polygon_ptr = reg.get<qlib::Polygon::s_ptr>(entity);
        auto& points = polygon_ptr->points;

        // 获取当前点
        pos = getNowPoint(query, points[points.size() - 2]);

        // 修改最后一个点，再加一个点
        points.back() = pos;
        points.emplace_back(pos);

        // 通知外部更新
        update_cache_obj(reg, event_writer, layout_cmd, entity, param);
        param.clear_tag = true;
        param.is_moveing = false;
      }
    }
  }

  // 更新逻辑
  if (param.state == State::Upatde) {
    // 获取点集
    auto& polygon_ptr = reg.get<qlib::Polygon::s_ptr>(entity);
    auto& points = polygon_ptr->points;

    // 获取当前点
    pos = getNowPoint(query, points[points.size() - 2]);

    // 修改最后一个点
    points.back() = pos;

    // 通知外部更新
    update_cache_obj(reg, event_writer, layout_cmd, entity, param);
    param.clear_tag = true;
    param.is_moveing = true;
  }

  // 完成逻辑
  if (param.state == State::Complete) {
    /// 获取点集，退出最后一个
    auto polygon_ptr = reg.get<qlib::Polygon::s_ptr>(entity);
    auto& points = polygon_ptr->points;
    points.pop_back();

    // 满足要求
    if (points.size() >= 3) {
      // 通知外部添加
      add_obj(reg, event_writer, layout_cmd, entity, undoRedoModule, cell, param, query, state);
      param.clear_tag = true;

      // // undoRedo
      // undoRedoModule.start(cell);
      // undoRedoModule.add(entity);
      // undoRedoModule.end();
    } else {
      // 不满足，通知外部删除
      delete_cache_obj(reg, event_writer, layout_cmd, param.entity, param);
      param.clear_tag = true;
    }

    // 重置参数
    param.state = State::None;
    param.entity = entt::null;

    auto& absorbModule = query.get_resource<qbe::adsorb::AdsorbModel>();
    absorbModule.close_diagonal_start();
  }

  // 结束的状态转换
  stateTransformEnd(param.state);
}

void Plugin::build(ecs::App& app) {
  app.add_stage<InitStage>();
  app.add_stage<UpdateStage>();

  app.init_event<Event>();

  app.add_systems<InitStage>(init);
  app.add_systems<UpdateStage>(update);
  app.add_systems<ecs::stage::Last>(clear_tag);
}

}  // namespace qbe::draw::polygon